package main

import (
	"fmt"
	"net"
	"sort"
	"time"
)

type result struct {
	port   int
	status bool
}

func worker(ports chan int, results chan *result) {
	for p := range ports {
		address := fmt.Sprintf("127.0.0.1:%d", p)
		conn, err := net.Dial("tcp", address)
		if err != nil {
			results <- &result{p, false}
			continue
		}
		conn.Close()
		results <- &result{p, true}
	}
}

// goroutine (worker)池并发版TCP端口扫描器
func main() {
	start := time.Now()

	ports := make(chan int, 100)
	results := make(chan *result)

	var openedPorts []int
	var closedPorts []int

	for i := 0; i < cap(ports); i++ {
		go worker(ports, results)
	}

	go func() {
		for i := 1; i <= 1024; i++ {
			ports <- i
		}
	}()

	for i := 1; i <= 1024; i++ {
		res := <-results
		if res.status {
			openedPorts = append(openedPorts, res.port)
		} else {
			closedPorts = append(closedPorts, res.port)
		}
	}

	close(ports)
	close(results)

	sort.Ints(openedPorts)
	sort.Ints(closedPorts)

	for _, port := range closedPorts {
		fmt.Printf("%d closed.\n", port)
	}

	fmt.Println()

	for _, port := range openedPorts {
		fmt.Printf("%d opened.\n", port)
	}

	elapsed := time.Since(start) / 1e9
	fmt.Printf("\n\n%d seconds!", elapsed)
}
